package com.transaction.demo.notify.mq;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.Map;
import java.util.Optional;

import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

import com.google.gson.reflect.TypeToken;
import com.transaction.demo.common.enums.ResponseExceptionEnum;
import com.transaction.demo.common.util.JsonUtils;
import com.transaction.demo.common.util.OkHttpUtil;
import com.transaction.demo.common.util.Result;
import com.transaction.demo.common.util.StringUtil;
import com.transaction.demo.message.MessageService;
import com.transaction.demo.message.vo.req.TransactionMessageAddReqVo;
import com.transaction.demo.notify.config.NotifyConfig;
import com.transaction.demo.notify.enums.NotifyStatusEnum;
import com.transaction.demo.notify.service.NotifyRecordLogService;
import com.transaction.demo.notify.service.NotifyRecordService;
import com.transaction.demo.notify.vo.req.NotifyRecordLogAddReqVo;
import com.transaction.demo.notify.vo.req.NotifyRecordUpdateReqVo;
import com.transaction.demo.notify.vo.resp.NotifyRecordRespVo;

@Slf4j
@Service
@RocketMQMessageListener(consumerGroup = "merchant_http_notify", topic = "notify")
public class NotifyHttpMessageListener implements RocketMQListener<String> {

	@Autowired
	private NotifyRecordService notifyRecordService;

	@Autowired
	private NotifyRecordLogService notifyRecordLogService;

	@Autowired
	private NotifyConfig config;

	@Autowired
	private MessageService messageService;

	@Override
	public void onMessage(String s) {
		log.info("发送http通知服务接收到消息：{}", s);

		NotifyRecordRespVo params = JsonUtils.fromJson(s, NotifyRecordRespVo.class);
		assert params != null;
		int times = params.getNotifyTimes();

		try {
			log.info("第{}通知商户参数：{}", times, JsonUtils.toJson(params));
			String postForm = OkHttpUtil.postForm(params.getUrl(), params);

			Result<String> result = JsonUtils.fromJson(postForm, new TypeToken<Result<String>>() {
			}.getType());
			log.info("通第{}知商户响应：{}", times, JsonUtils.toJson(result));

			NotifyRecordUpdateReqVo updateReqVo = new NotifyRecordUpdateReqVo();
			BeanUtils.copyProperties(params, updateReqVo);
			updateReqVo.setEditTime(new Date());

			boolean b = Optional.ofNullable(result)
					.filter(x -> x.getCode().equals(ResponseExceptionEnum.SUCCESS.getCode()))
					.filter(x -> "success".equals(x.getData())).isPresent();

			updateReqVo.setStatus(b ? NotifyStatusEnum.SUCCESS.name() : NotifyStatusEnum.FAILED.name());

			log.info("更新通知记录：{}", JsonUtils.toJson(updateReqVo));
			notifyRecordService.updateNotifyRecord(updateReqVo);

			if (!b) {
				sendFailMessage(JsonUtils.toJson(updateReqVo), times);
			}

			saveRecordLog(params, JsonUtils.toJson(result), "200");
		} catch (IOException e) {
			log.info("第{}通知商户异常：{}",times, s);
			NotifyRecordUpdateReqVo recordUpdateReqVo = new NotifyRecordUpdateReqVo();
			BeanUtils.copyProperties(params, recordUpdateReqVo);
			recordUpdateReqVo.setEditTime(new Date());
			recordUpdateReqVo.setStatus(NotifyStatusEnum.HTTP_REQUEST_FALIED.name());
			notifyRecordService.updateNotifyRecord(recordUpdateReqVo);

			saveRecordLog(params, "", "0");

			//重新发送延时任务
			sendFailMessage(JsonUtils.toJson(params), times);
		}

	}

	/**
	 * 记录日志记录
	 *
	 * @param params 参数
	 * @param result 响应
	 * @param httpStatus http状态
	 * @author 马庆智
	 * @date: 2023/5/16 15:49
	 */
	private void saveRecordLog(NotifyRecordRespVo params, String result, String httpStatus) {
		NotifyRecordLogAddReqVo logAddReqVo = new NotifyRecordLogAddReqVo();
		logAddReqVo.setId(StringUtil.get32UUID());
		logAddReqVo.setVersion(0);
		logAddReqVo.setEditTime(new Date());
		logAddReqVo.setCreateTime(new Date());
		logAddReqVo.setNotifyId(params.getId());
		logAddReqVo.setRequest(JsonUtils.toJson(params));
		logAddReqVo.setResponse(result);
		logAddReqVo.setMerchantNo(params.getMerchantNo());
		logAddReqVo.setMerchantOrderNo(params.getMerchantOrderNo());
		logAddReqVo.setHttpStatus(httpStatus);

		log.info("记录日志记录: {}", JsonUtils.toJson(logAddReqVo));
		notifyRecordLogService.saveNotifyRecordLog(logAddReqVo);
	}

	/**
	 * 发送延迟消息
	 *
	 * @param body 消息
	 * @param times 次数
	 * @author 马庆智
	 * @date: 2023/5/16 15:44
	 */
	private void sendFailMessage(String body, int times) {
		if (times >= config.maxSendTimes) {
			log.info("消息发送次数超过：{}", config.maxSendTimes);
			return;
		}
		times = times + 1;

		NotifyRecordRespVo params = JsonUtils.fromJson(body, NotifyRecordRespVo.class);
		assert params != null;
		params.setNotifyTimes(times);

		TransactionMessageAddReqVo messageAddReqVo = new TransactionMessageAddReqVo();
		messageAddReqVo.setMessageId(StringUtil.get32UUID());
		messageAddReqVo.setMessageBody(JsonUtils.toJson(params));
		messageAddReqVo.setConsumerQueue(config.mqName);
		messageAddReqVo.setMessageSendTimes((short) times);
		log.info("第{}发送延时消息通知：{}", times, JsonUtils.toJson(messageAddReqVo));
		messageService.directSendMessage(messageAddReqVo);
	}
}
